#pragma once

#include <iostream>
#include <string>
#include <cstdio>
#include <set>
#include "Command.hpp"
#include "InetAddr.hpp"
#include "Log.hpp"

using namespace LogModule;
//通过白名单机制限制可执行的远程命令
//白名单机制：通过std::set存储允许执行的命令
//（如ls、pwd、whoami等），严格匹配输入的命令字符串。
class Command
{
public:
    // ls -a && rm -rf
    // ls -a; rm -rf
    Command()
    {
        // 严格匹配
        _WhiteListCommands.insert("ls");
        _WhiteListCommands.insert("pwd");
        _WhiteListCommands.insert("ls -l");
        _WhiteListCommands.insert("touch haha.txt");
        _WhiteListCommands.insert("who");
        _WhiteListCommands.insert("whoami");
    }
    bool IsSafeCommand(const std::string &cmd)
    {
        auto iter = _WhiteListCommands.find(cmd);
        return iter != _WhiteListCommands.end();
    }

	//addr客户端的网络地址
	//对输入的命令进行安全性检查，若检查通过就执行该命令，最后返回执行结果
    std::string Execute(const std::string &cmd, InetAddr &addr)
	{
		// 1. 属于白名单命令
		if(!IsSafeCommand(cmd))
		{
			return std::string("坏人");
		}

		std::string who = addr.StringAddr();

		// 2. 执行命令
		// popen 函数来执行命令。popen 会创建一个管道，
		//并且启动一个子进程去执行 shell 命令，最后返回一个文件指针。
		//要是 popen 执行失败（返回 nullptr），就会返回错误信息，提示用户要执行的命令不存在。
		FILE *fp = popen(cmd.c_str(), "r");
		if(fp == nullptr)
		{
			return std::string("你要执行的命令不存在: ") + cmd;
		}
		std::string res;
		char line[1024];
		//fgets 函数从管道里读取命令的输出内容
		while(fgets(line, sizeof(line), fp))
		{
			res += line;
		}
		pclose(fp);
		std::string result = who + "execute done, result is: \n" + res;
        LOG(LogLevel::DEBUG) << result;
        return result;
	}
    ~Command()
    {}
private:
    // 受限制的远程执行
    std::set<std::string> _WhiteListCommands;
};